﻿using System;
using System.Collections.Generic;
//using System.Linq;
//using System.Text;
using System.IO;
using AMS.DeDuplicator.CommonLayer;
using AMS.DeDuplicator.CommonLayer.Composite;

namespace AMS.DeDuplicator.BusinessLayer
{
    public /*abstract*/ class DuplicateIdentifier : IDuplicateIdentifier
    {
        private Dictionary<UniquePropertySet, string> _mappings;

        #region Delegates
        // Does using delegates really add anything if I'm sacrificing abstraction for composition?
        // No loss. A consumer can still sublass and set these, and _getHashValue is REQUIRED at construction
        protected HookDelegate _preHashHook;
        public HookDelegate PreHashHook { set { _preHashHook = value; } }

        protected GetHashValueDelegate _getHashValue;
        // is this setter necessary?
        public GetHashValueDelegate GetHashValueDelegate
        {
            set
            {
                // TODO: ensure user can't change this delegate in the middle of a Find Duplicates operation
                InputValidator.ValidateNotNull(value);
                _getHashValue = value;
            }
        }

        protected HookDelegate _postHashHook;
        public HookDelegate PostHashHook { set { _postHashHook = value; } }
        #endregion

        public DuplicateIdentifier(GetHashValueDelegate getHashValueDelegate)
        {
            InputValidator.ValidateNotNull(getHashValueDelegate);

            _getHashValue = getHashValueDelegate;
            _mappings = new Dictionary<UniquePropertySet, string>();
        }

        public bool CheckFile(string filePath, out UniquePropertySet properties, out string primeMatchPath)
        {
            // template method
            // Step 0: validate input
            InputValidator.ValidateNotNull(filePath);
            InputValidator.ValidateFileExists(filePath);

            // Step 1: get file size
            long sizeInBytes = FileComponent.GetSizeInBytes(filePath);

            // Hook before hash
            if (_preHashHook != null)
                _preHashHook(null);

            // Step 2: get file hash // can be subbed out
            string hashValue = _getHashValue(filePath);

            // hook after hash
            if (_postHashHook != null)
                _postHashHook(null);

            // Step 3: create unique identifier object
            properties = new UniquePropertySet(hashValue, sizeInBytes);

            // Step 4: check _mappings for match
            if (!_mappings.ContainsKey(properties))
            {
                // this is an unmatched file, so register it as the first
                _mappings.Add(properties, filePath);
                primeMatchPath = null;
                return false;
            }
            else
            {
                // return the filepath to the first match
                primeMatchPath = _mappings[properties];
                return true;
            }
        }

        public void Reset()
        {
            _mappings.Clear();
        }
    }
}
